package com.globallogic.javatrainings.sergiiivanov.controller;

import com.globallogic.javatrainings.sergiiivanov.model.Building;
import com.globallogic.javatrainings.sergiiivanov.model.Const;
import com.globallogic.javatrainings.sergiiivanov.model.Lecture;
import com.globallogic.javatrainings.sergiiivanov.model.MyArray;
import com.globallogic.javatrainings.sergiiivanov.model.Room;
import com.globallogic.javatrainings.sergiiivanov.model.Room.RoomType;
import com.globallogic.javatrainings.sergiiivanov.model.University;
import com.globallogic.javatrainings.sergiiivanov.model.UniversityFailure;
import com.globallogic.javatrainings.sergiiivanov.model.UniversityWarning;
import com.globallogic.javatrainings.sergiiivanov.resources.ErrorCodes;
import com.globallogic.javatrainings.sergiiivanov.view.BuildingsManagementPage;

class BuildingDetailsController extends BasicController {
    private enum States {
        ADD_ROOM,
        ASSIGN_PERSON_TO_ROOM,
        DELETE_BUILDING_CONFIRMATION,
        DELETE_ROOM_CONFIRMATION,
        SETUP_ROOM,
        SHOW_DETAILS,
        SHOW_ROOM_DETAILS,
        SHOW_LECTURES
    }

    private int command;
    private States currentState;
    private BuildingsManagementPage page = new BuildingsManagementPage();
    private University university;
    private Building building;
    private Room room;

    BuildingDetailsController(Building b) {
        building = b;
    }

    @Override
    BasicController initiate(University u) throws UniversityFailure {
        this.university = u;
        validateData();

        if (currentState == States.SHOW_DETAILS) {
            return buildingGeneralDetailsPage();
        }
        if (currentState == States.ADD_ROOM) {
            return addRoomWizard();
        }
        if (currentState == States.ASSIGN_PERSON_TO_ROOM) {
            return assignPersonWizard();
        }
        if (currentState == States.SETUP_ROOM) {
            return setupRoomWizard();
        }
        if (currentState == States.SHOW_ROOM_DETAILS) {
            return roomDetails();
        }
        if (currentState == States.DELETE_BUILDING_CONFIRMATION) {
            return deleteBuilding();
        }
        if (currentState == States.DELETE_ROOM_CONFIRMATION) {
            return deleteRoom();
        }
        if (currentState == States.SHOW_LECTURES) {
            return showAppointedLectures();
        }
        currentState = States.SHOW_DETAILS;
        return this;
    }

    private void validateData() throws UniversityFailure {
        if (university == null || building == null) {
            throw new UniversityFailure(ErrorCodes.BUILDING_STORAGE_FAILURE);
        }
    }

    private BasicController addRoomWizard() throws UniversityFailure {
        page.addRoomWizard();
        String roomName = InputController.readString();
        try {
            building.addRoom(roomName);
            currentState = States.SETUP_ROOM;
            room = building.getRoomByIndex(building.countRooms() - 1);
        } catch (UniversityWarning e) {
            page.error("Failed to add room", e.getMessage());
            currentState = States.SHOW_DETAILS;
        }
        return this;
    }

    private BasicController assignPersonWizard() throws UniversityFailure {
        String[] people;
        people = university.personnel.getPersonnelList();
        page.pageSelectPersonToAssign(people);
        int selectedPerson = InputController.readInt();
        currentState = States.SHOW_ROOM_DETAILS;
        if (selectedPerson < 0 || selectedPerson >= people.length) {
            return this;
        }
        try {
            room.setResponsiblePerson(university.personnel.getPersonnelByIndex(selectedPerson));
        } catch (Exception e) {
            page.error("Failed to assign personnel", e.getMessage());
            currentState = States.SHOW_DETAILS;
        }
        return this;
    }

    private BasicController buildingGeneralDetailsPage() throws UniversityFailure {
        String[] rooms;
        rooms = building.getRooms().toNamesList();
        page.pageBuildingGeneralDetails(university.getTitle(), building.getName(), rooms);
        readCommand();
        int addnew = 1 + rooms.length;
        int deletebuilding = 3 + rooms.length;
        int rename = 2 + rooms.length;
        if (command == 0) {
            return null;
        }
        if (command == addnew) {
            currentState = States.ADD_ROOM;
            return this;
        }
        if (command == deletebuilding) {
            currentState = States.DELETE_BUILDING_CONFIRMATION;
            return this;
        }
        if (command == rename) {
            return renameBuilding();
        }
        currentState = States.SHOW_ROOM_DETAILS;
        try {
            room = building.getRoomByIndex(command - 1);
        } catch (UniversityWarning e) {
            page.error("Error: unable to get selected room", e.getMessage());
            currentState = States.SHOW_DETAILS;
        }
        return this;
    }

    private BasicController renameBuilding() {
        page.pageRenameBuilding(building.getName());
        String newName = InputController.readString().trim();
        if (!Const.STRING_EMPTY.equals(newName)) {
            try {
                building.setName(newName);
            } catch (UniversityWarning e) {
                page.error("Failed to rename building", e.getMessage());
            }
        }
        return this;
    }

    private BasicController deleteBuilding() {
        page.pageConfirmDeletion(building.getName());
        if (yes()) {
            try {
                university.buildings.removeBuilding(building);
            } catch (UniversityWarning e) {
                page.error("Failed to remove building", e.getMessage());
            }
        }
        currentState = null;
        return null;
    }

    private BasicController deleteRoom() {
        page.pageDeleteRoomConfirmation();
        if (yes()) {
            try {
                building.removeRoom(room);
            } catch (UniversityWarning w) {
                page.error("ERROR: Failed to remove room", w.getMessage());
            }

        }
        currentState = States.SHOW_DETAILS;
        return this;
    }

    private BasicController showAppointedLectures() throws UniversityFailure {
        MyArray<Lecture> appointedLectures = room.getLinkedLectures();
        String[][] lecturesTable = new String[appointedLectures.size()][2];
        for (int i = 0; i < appointedLectures.size(); i++) {
            lecturesTable[i][0] = appointedLectures.get(i).getCourseName();
            lecturesTable[i][1] = appointedLectures.get(i).getName();
        }
        page.appointedLecturesList(building.getName(), room.getName(), lecturesTable);
        currentState = States.SHOW_ROOM_DETAILS;
        readCommand();
        return this;
    }

    private void readCommand() {
        command = InputController.readInt();

    }

    private BasicController roomDetails() {
        String[] roomDetails;
        try {
            roomDetails = getRoomDetails();
        } catch (UniversityWarning e) {
            page.error("Failed to display room details ", e.getMessage());
            currentState = States.SHOW_DETAILS;
            return this;
        }
        page.pageShowRoomDetails(
                university.getTitle(),
                building.getName(),
                roomDetails);
        readCommand();
        switch (command) {
        case 0:
            currentState = States.SHOW_DETAILS;
            return this;
        case 1:
            currentState = States.SETUP_ROOM;
            return this;
        case 2:
            currentState = States.SHOW_LECTURES;
            return this;
        case 3:
            currentState = States.DELETE_ROOM_CONFIRMATION;
            return this;
        default:
            return this;
        }
    }

    private String[] getRoomDetails() throws UniversityWarning {
        String[] roomDetails = new String[4];
        if (room != null) {
            roomDetails[0] = room.getName();
            roomDetails[1] = room.getTypePrint();
            roomDetails[2] = Integer.valueOf(room.getCapacity()).toString();
            roomDetails[3] = room.getResponsiblePerson() == null ? "not assigned" : room.getResponsiblePerson().getName();
        } else {
            throw new UniversityWarning("Room is not selected or found");
        }
        return roomDetails;
    }

    private BasicController setupRoomWizard() throws UniversityFailure {
        validateData();
        currentState = States.SHOW_ROOM_DETAILS;
        page.pageRoomSetup(university.getTitle(), building.getName(), room.getName());
        page.pageRoomSetup_newId();
        String newName = InputController.readString().trim();
        try {
            room.setName(newName);
        } catch (UniversityWarning e1) {
            page.error("Failed to rename", e1.getMessage());
            return this;
        }
        page.pageRoomSetup_newType(Room.RoomType.getNamesList());
        Room.RoomType newType = null;
        try {
            newType = Room.RoomType.values()[InputController.readInt()];
        } catch (Exception e) {
            newType = RoomType.OTHER;
        }
        if (newType.equals(RoomType.AUDITORIUM))
            try {
                room.setToAuditorium();
            } catch (UniversityWarning e1) {
                page.error("Unable to setup room", e1.getMessage());
                return this;
            }
        if (newType.equals(RoomType.LABORATORY))
            try {
                room.setToLaboratory();
            } catch (UniversityWarning e1) {
                page.error("Unable to setup room", e1.getMessage());
                return this;
            }
        if (newType.equals(RoomType.OTHER))
            try {
                room.setToOther();
            } catch (UniversityWarning e1) {
                page.error("Unable to setup room", e1.getMessage());
                return this;
            }
        page.pageRoomSetup_newCapacity();
        int newCapacity = InputController.readInt();
        try {
            room.setCapacity(newCapacity);
        } catch (UniversityWarning e) {
            page.error("Failed to update capacity", e.getMessage());
            return this;
        }
        return this;
    }

}
